package com.sjb.stock.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.sjb.stock.constant.StockConstant;
import com.sjb.stock.pojo.entity.SysUser;
import com.sjb.stock.pojo.mapper.SysUserMapper;
import com.sjb.stock.service.UserService;
import com.sjb.stock.utils.IdWorker;
import com.sjb.stock.vo.req.LoginReqVo;
import com.sjb.stock.vo.resp.LoginRespVo;
import com.sjb.stock.vo.resp.R;
import com.sjb.stock.vo.resp.ResponseCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @FileName UserServiceImpl
 * @Description 用户服务实现类
 * @Author chm
 * @date 2025/6/21
 **/
@Service("UserService")
@Slf4j
public class UserServiceImpl implements UserService {
    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private IdWorker idWorker;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    /**
     * @param userName 用户名，用于查询对应的系统用户。
     * @return 返回与指定用户名对应的系统用户对象；如果未找到匹配的用户，则返回null。
     * @description: 根据用户名查询系统用户信息。
     * @author chm
     * @date 2025/6/21
     **/
    @Override
    public SysUser getUserByUserName(@PathVariable String userName) {
        return sysUserMapper.getUserByUserName(userName);
    }

    public R<LoginRespVo> login(LoginReqVo loginReqVo) {
        // 判断参数是否合法
        if (loginReqVo == null || StringUtils.isBlank(loginReqVo.getUsername()) || StringUtils.isBlank(loginReqVo.getPassword())) {
            return R.error(ResponseCode.DATA_ERROR);
        }
        // 判断验证是否存在
        if (StringUtils.isBlank(loginReqVo.getCode()) || StringUtils.isBlank(loginReqVo.getSessionId())) {
            return R.error(ResponseCode.CHECK_CODE_ERROR);
        }
        // 判断redis上的验证码是否过期
        String redisCode = redisTemplate.opsForValue().get(StockConstant.CHECK_PREFIX + loginReqVo.getSessionId());
        if (StringUtils.isBlank(redisCode)) {
            return R.error(ResponseCode.CHECK_CODE_TIMEOUT);
        }
        // 判断验证码相同，忽略大小写
        if (!redisCode.equalsIgnoreCase(loginReqVo.getCode())) {
            return R.error(ResponseCode.CHECK_CODE_ERROR);
        }
        // 判断账号是否存在
        SysUser dbUser = sysUserMapper.getUserByUserName(loginReqVo.getUsername());
        if (dbUser == null) {
            return R.error(ResponseCode.ACCOUNT_NO_EXISTS_ERROR);
        }
        // 判断密码是否正确
        if (!passwordEncoder.matches(loginReqVo.getPassword(), dbUser.getPassword())) {
            return R.error(ResponseCode.USERNAME_OR_PASSWORD_ERROR);
        }
        // 响应
        LoginRespVo loginRespVo = new LoginRespVo();

        // 不使用工具 需要手写一堆重复的代码
        // loginRespVo.setId(dbUser.getId())
        // loginRespVo.setPhone(dbUser.getPhone())
        // loginRespVo.setUsername(dbUser.getUsername())
        // loginRespVo.setNickName(dbUser.getNickName())

        // 使用spring下合并工具
        BeanUtils.copyProperties(dbUser, loginRespVo);

        return R.ok(loginRespVo);
    }

    /**
     * @return com.sjb.stock.vo.resp.R<java.util.Map>
     * @description: 生成图片二维码
     * @author chm
     * @date 2025/7/15
     **/

    public R<Map> getCaptchaCode() {
        // 生成图片验证码(width: 图片宽度、height: 图片高度、codeCount: 验证码的长度、lineCount: 干扰线的数量)
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(140, 40, 4, 5);
        // 获取验证码
        String code = lineCaptcha.getCode();
        // 获取base64编码的图片
        String imageBase64 = lineCaptcha.getImageBase64();

        // 生成session_id 转化成字符串 避免前端精度丢失
        String sessionId = String.valueOf(idWorker.nextId());
        // 日志打印
        log.info("当前生成图片的校验 code: {}, session_id: {}", code, sessionId);
        // 将session_id 作为key、code作为value保存到redis中（用redis模拟session行为，设置过期时间）
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        ops.set(StockConstant.CHECK_PREFIX + sessionId, code, 30, TimeUnit.SECONDS);
        // 封装数据并返回
        Map<String, String> map = new HashMap<>();
        map.put("imageData", imageBase64);
        map.put("sessionId", sessionId);
        return R.ok(map);
    }
}
